// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//


#pragma once

#include <pollux/type/cpp_to_type.h>
#include <pollux/type/type.h>

namespace kumo::pollux::exec {
    class StringWriter;

    template<bool nullable, typename V>
    class ArrayView;

    template<typename T>
    using NullFreeArrayView = ArrayView<false, T>;

    template<typename T>
    using NullableArrayView = ArrayView<true, T>;

    template<bool nullable, typename K, typename V>
    class MapView;

    template<typename K, typename V>
    using NullFreeMapView = MapView<false, K, V>;

    template<typename K, typename V>
    using NullableMapView = MapView<true, K, V>;

    template<bool nullable, typename... T>
    class RowView;

    template<typename... T>
    using NullFreeRowView = RowView<false, T...>;

    template<typename... T>
    using NullableRowView = RowView<true, T...>;

    template<bool nullable, typename T>
    class VariadicView;

    template<typename T>
    using NullFreeVariadicView = VariadicView<false, T>;

    template<typename T>
    using NullableVariadicView = VariadicView<true, T>;

    template<typename V>
    class ArrayWriter;

    template<typename... T>
    class RowWriter;

    template<typename K, typename V>
    class MapWriter;

    class GenericView;

    class GenericWriter;

    namespace detail {
        template<typename T>
        struct resolver {
            using in_type = typename CppToType<T>::NativeType;
            using null_free_in_type = in_type;
            using out_type = typename CppToType<T>::NativeType;
        };

        template<typename K, typename V>
        struct resolver<Map<K, V> > {
            using in_type = NullableMapView<K, V>;
            using null_free_in_type = NullFreeMapView<K, V>;
            using out_type = MapWriter<K, V>;
        };

        template<typename... T>
        struct resolver<Row<T...> > {
            using in_type = NullableRowView<T...>;
            using null_free_in_type = NullFreeRowView<T...>;
            using out_type = RowWriter<T...>;
        };

        template<typename V>
        struct resolver<Array<V> > {
            using in_type = NullableArrayView<V>;
            using null_free_in_type = NullFreeArrayView<V>;
            using out_type = ArrayWriter<V>;
        };

        template<typename P, typename S>
        struct resolver<ShortDecimal<P, S> > {
            using in_type = int64_t;
            using null_free_in_type = in_type;
            using out_type = int64_t;
        };

        template<typename P, typename S>
        struct resolver<LongDecimal<P, S> > {
            using in_type = int128_t;
            using null_free_in_type = in_type;
            using out_type = int128_t;
        };

        template<>
        struct resolver<Varchar> {
            using in_type = StringView;
            using null_free_in_type = in_type;
            using out_type = StringWriter;
        };

        template<>
        struct resolver<Varbinary> {
            using in_type = StringView;
            using null_free_in_type = in_type;
            using out_type = StringWriter;
        };

        template<>
        struct resolver<Date> {
            using in_type = int32_t;
            using null_free_in_type = in_type;
            using out_type = int32_t;
        };

        template<>
        struct resolver<IntervalDayTime> {
            using in_type = int64_t;
            using null_free_in_type = in_type;
            using out_type = int64_t;
        };

        template<>
        struct resolver<IntervalYearMonth> {
            using in_type = int32_t;
            using null_free_in_type = in_type;
            using out_type = int32_t;
        };

        template<typename T>
        struct resolver<std::shared_ptr<T> > {
            using in_type = std::shared_ptr<T>;
            using null_free_in_type = in_type;
            using out_type = std::shared_ptr<T>;
        };

        template<typename T>
        struct resolver<Variadic<T> > {
            using in_type = NullableVariadicView<T>;
            using null_free_in_type = NullFreeVariadicView<T>;
            // Variadic cannot be used as an out_type
        };

        template<typename T, bool comparable, bool orderable>
        struct resolver<Generic<T, comparable, orderable> > {
            using in_type = GenericView;
            using null_free_in_type = in_type;
            using out_type = GenericWriter;
        };

        template<typename T, bool providesCustomComparison>
        struct resolver<CustomType<T, providesCustomComparison> > {
            using in_type = std::conditional_t<
                providesCustomComparison,
                CustomTypeWithCustomComparisonView<
                    typename resolver<typename T::type>::in_type>,
                typename resolver<typename T::type>::in_type>;
            using null_free_in_type = std::conditional_t<
                providesCustomComparison,
                CustomTypeWithCustomComparisonView<
                    typename resolver<typename T::type>::null_free_in_type>,
                typename resolver<typename T::type>::null_free_in_type>;
            using out_type = typename resolver<typename T::type>::out_type;
        };
    } // namespace detail

    struct VectorExec {
        template<typename T>
        using resolver = typename detail::template resolver<T>;
    };
} // namespace kumo::pollux::exec
